package com.wangjiang.foundation.mybatis.params;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wangjiang.foundation.common.util.CommonUtils;
import com.wangjiang.foundation.common.util.StringUtil;
import com.wangjiang.foundation.mybatis.entity.BaseEntity;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 返回一个querywrapper
 *
 * @author wangjiang
 * @date 2021-01-03 03:28:41
 */
public class QueryParams extends Param {

    /**
     * 是否分页
     */
    @Getter
    @Setter
    private boolean paging = true;

    @Getter
    @Setter
    private Integer pageNo = 0;

    @Getter
    @Setter
    private Integer pageSize = 10;

    @Getter
    @Setter
    private List<OrderParam> orders = new ArrayList<>();

    /**
     * 构建mybatis查询条件
     *
     * @author wangjiang
     * @date 2021-01-03 04:09:51
     */
    public <T extends BaseEntity> QueryWrapper<T> build(QueryWrapper<T> query) {
        for (Term term : getTerms()) {
            query = build(query, term);
        }
        buildOrders(query);
        return query;
    }

    private <T extends BaseEntity> void buildOrders(QueryWrapper<T> query) {
        if (!orders.isEmpty()) {
            for (OrderParam order : orders) {
                String column = StringUtil.underscoreName(order.getColumn());

                if (Objects.equals(order.getOrder(), OrderEnum.DESC)) {
                    query.orderByDesc(column);
                } else {
                    query.orderByAsc(column);
                }
            }
        }
    }


    private <T extends BaseEntity> QueryWrapper<T> build(QueryWrapper<T> query, Term term) {
        query = addWrapQuery(query, term);
        return query;
    }


    /**
     * and or
     *
     * @author wangjiang
     * @date 2021-01-11 11:43:20
     */
    private <T extends BaseEntity> QueryWrapper<T> addWrapQuery(QueryWrapper<T> query, Term term) {

        boolean nullTerm = StringUtil.isNull(term.getColumn());

        if (nullTerm && CommonUtils.isNull(term.getTerms())) {
            return query;
        }

        if (Objects.equals(term.getType(), Term.Type.or)) {
            query = query.or();
        }

        query.and(innerWrapper -> {
            innerWrapper = buildQuery(innerWrapper, term.getColumn(), term.getTermType(), term.getValue());
            for (Term termTerm : term.getTerms()) {
                if (Objects.equals(termTerm.getType(), Term.Type.or))
                    innerWrapper = innerWrapper.or();
                innerWrapper = buildQuery(innerWrapper, termTerm.getColumn(), termTerm.getTermType(), termTerm.getValue());
            }
            return innerWrapper;
        });

        return query;
    }

    private <T extends BaseEntity> QueryWrapper<T> buildQuery(QueryWrapper<T> query, String column, TermEnum termType, Object value) {
        // 驼峰转下换线
        column = StringUtil.underscoreName(column);
        switch (termType) {
            case eq:
                query = query.eq(column, value);
                break;
            case not:
                query = query.ne(column, value);
                break;
            case gt:
                query = query.gt(column, value);
                break;
            case gte:
                query = query.ge(column, value);
                break;
            case lt:
                query = query.lt(column, value);
                break;
            case lte:
                query = query.le(column, value);
                break;
            case like:
                query = query.like(column, value);
                break;
            case nlike:
                query = query.notLike(column, value);
                break;
            case in:
                query = query.in(column, value);
                break;
            case nin:
                query = query.notIn(column, value);
                break;
            case isnull:
                query = query.isNull(column);
                break;
            case notnull:
                query = query.isNotNull(column);
                break;
            case btw:
                List<Object> arr = (List<Object>) value;
                if (arr.size() != 2) {
                    throw new RuntimeException("btw arr error!");
                }
                query.between(column, arr.get(0), arr.get(1));
                break;
            case nbtw:
                List<Object> arr2 = (List<Object>) value;
                if (arr2.size() != 2) {
                    throw new RuntimeException("btw arr error!");
                }
                query.notBetween(column, arr2.get(0), arr2.get(1));
                break;
            default:
                ;
        }
        return query;
    }

    public QueryParams addTerms(List<Term> terms) {
        this.terms.addAll(terms);
        return this;
    }

    public void setDefaultOrder() {
        OrderParam orderParam = new OrderParam();
        orderParam.setColumn("createdTime");
        orderParam.setOrder(OrderEnum.DESC);
        orders.add(orderParam);
    }
}
